<template>
  <div class="page_root" :key="queryUpdateFlag" data-page-name="经营看板" data-page-identification="u_fqj38a73v0">
    <a-spin :spinning="pageLoading.loading" :tip="pageLoading.tip">
      <!-- begin vid_pwix3i6a8b 自定义模板_r3koyasnpg -->

      <!--      里程碑进度表弹窗-->
      <a-modal :visible="ftfState.modalVisible" title="总体经营仪表盘" width="80%" centered :footer="null" @cancel="ftfState.modalVisible = false" :mask-closable="false" destroy-on-close>
        <div class="search-radio">
          <a-radio-group v-model:value="ftfState.radioValue" button-style="solid">
            <a-radio-button value="全部">全部</a-radio-button>
            <a-radio-button value="基础信息">基础信息</a-radio-button>
            <a-radio-button value="项目阶段">项目阶段</a-radio-button>
            <a-radio-button value="其他">其他</a-radio-button>
          </a-radio-group>
        </div>
        <div class="kb-table-box">
          <a-table
            :columns="filteredColumns"
            :dataSource="ftfState.dataSource"
            :scroll="{ x: '1000px', y: 700 }"
            :pagination="false"
            :loading="ftfState.tableLoading"
            bordered
            @resizeColumn="handleResizeColumn"
            :showSorterTooltip="false"
            @change="handleTableChange"
            ref="tableRef"
          >
            <template #headerCell="{ column, title }">
              <template v-if="['进展', '问题&风险', '预计开始', '预计结束'].includes(title)">
                <div class="text-line-div">{{ title }}</div>
              </template>
              <template v-if="title === '项目状态'">
                <div class="text-line-div">
                  {{ title }}
                </div>
              </template>
              <template v-if="title === '工厂名称'">
                <div class="text-line-div">
                  {{ title }}
                </div>
              </template>
              <template v-if="column.dataIndex === 'riskLevel'">
                <span>
                  {{ title }}
                  <a-tooltip>
                    <template #title>
                      <p class="risk-level-tool-tip">风险等级划分：</p>
                      <p class="risk-level-tool-tip">1、保底；</p>
                      <p class="risk-level-tool-tip">2、略有风险；</p>
                      <p class="risk-level-tool-tip">3、需要冲刺；</p>
                      <p class="risk-level-tool-tip">4、暂不强推</p>
                    </template>
                    <question-circle-outlined />
                  </a-tooltip>
                </span>
              </template>
            </template>

            <template #bodyCell="{ record, text, column, index }">
              <template v-if="column.fieldType !== 'FILE' && column.fieldType">
                <div class="db-click" @dblclick="showEditStatistics(column, record, index)">{{ text }}</div>
              </template>
              <template v-if="column.fieldType === 'FILE'">
                <div class="file-div" @dblclick="showEditStatistics(column, record, index)">
                  <template v-if="text">
                    <div v-for="(item, index) in JSON.parse(text)" :key="item.name">
                      <a-dropdown>
                        <a :title="item.name">{{ item.name }}</a>
                        <template #overlay>
                          <a-menu>
                            <a-menu-item>
                              <a-button type="link" size="small" :disabled="!item.type.startsWith('image')" @click="viewImage(item.url)">预览</a-button>
                            </a-menu-item>
                            <a-menu-item>
                              <a-button type="link" size="small" @click="downLoadFile(item)">下载</a-button>
                            </a-menu-item>
                          </a-menu>
                        </template>
                      </a-dropdown>
                    </div>
                  </template>
                  <template v-else>
                    <div class="file-div"></div>
                  </template>
                </div>
              </template>

              <template v-if="['项目阶段'].includes(column.title)">
                <div class="db-click" @dblclick="changeData(record, index)">{{ text }}</div>
              </template>
              <template v-if="column.dataIndex === 'progress'">
                <div class="progress-click" @dblclick="changeData(record, index)">
                  <a-tooltip :overlay-style="overStyle" v-if="record.progress">
                    <template #title>{{ record.progress }}</template
                    ><div class="omit-div">{{ text }} </div>
                  </a-tooltip>
                </div>
              </template>
              <template v-if="column.dataIndex === 'question'">
                <div class="question-div" @dblclick="changeData(record, index)">
                  <a-tooltip :overlay-style="overStyle" v-if="record.question">
                    <template #title
                      >{{ record.question }}【 {{ record.operator }}】【{{
                    record.operateTime

                      }}】</template
                    ><div class="omit-div-question"
                      ><span v-if="record.question">{{ text }}【 {{ record.operator }}】【{{ record.operateTime }}】</span></div
                    >
                  </a-tooltip>
                  <!--                                    <div class="plus-icon" @click="handleAddLhwt"><PlusCircleOutlined /></div>-->
                </div>
              </template>
              <template v-if="column.dataIndex === 'productionPlan'">
                <div class="productionPlan-div">
                  <a-tooltip :overlay-style="overStyle" v-if="record.productionPlan">
                    <template #title>{{ text }}</template
                    ><div class="omit-div-productionPlan" v-if="text">{{ text }}</div>
                  </a-tooltip>
                </div>
              </template>
              <template v-if="column.dataIndex === 'customerRelationship'">
                <div class="customerRelationship-div">
                  <a-tooltip :overlay-style="overStyle" v-if="record.customerRelationship">
                    <template #title>{{ text }}</template
                    ><div class="omit-div-customerRelationship"
                      ><span v-if="text">{{ text }}</span></div
                    >
                  </a-tooltip>
                </div>
              </template>
              <template v-if="column.dataIndex === 'count'">
                {{ index + 1 }}
              </template>
              <template
                v-if="
                            [
                                'modelExpectStartTime',
                                'modelExpectEndTime',
                                'testRunExpectStartTime',
                                'testRunExpectEndTime',
                                'runExpectStartTime',
                                'runExpectEndTime',
                                'checkExpectStartTime',
                                'checkExpectEndTime',
                                'verifyExpectStartTime',
                                'verifyExpectEndTime'
                            ].includes(column.dataIndex)
                        "
              >
                <div class="db-click" @dblclick="changeData(record, index)">{{ text }}</div>
              </template>
              <template v-if="column.dataIndex === 'supportors'">
                <div class="support-div" :title="text" @dblclick="changeData(record, index)">{{ text }}</div>
              </template>
              <template v-if="column.dataIndex === 'projectStatus'">
                <div v-if="record.projectStatus === '进行中'" class="db-click" @dblclick="changeData(record, index)" style="color: #3875ff">{{ text }}</div>
                <div v-if="record.projectStatus === '准备'" class="db-click" @dblclick="changeData(record, index)" style="color: #ffa940">{{ text }}</div>
                <div v-if="record.projectStatus === '完成'" class="db-click" @dblclick="changeData(record, index)" style="color: green">{{ text }}</div>
                <div v-if="!record.projectStatus" class="db-click" @dblclick="changeData(record, index)">{{
                text
                }}</div>
              </template>
              <template v-if="column.dataIndex === 'projectShortName'">
                <div class="db-click-name" @dblclick="changeData(record, index)">{{ text }}</div>
              </template>
            </template>
          </a-table>
        </div>
      </a-modal>

      <!--      里程碑进度表弹窗-->
      <div class="main-content" id="mainContent">
        <div class="top-title">
          <span>经营地图看板</span>
        </div>
        <ul class="legend">
          <li @click="onChangelegends(0)" :class="{gray:legendsDot[0] }">
            <i class="img icon icon-green"></i>
            偏差度20%以内
          </li>
          <li @click="onChangelegends(1)" :class="{gray:legendsDot[1]}">
            <i class="img icon icon-yellow"></i>
            {{ typeSelectIndex === 0 ? '偏差度21%-40%': '偏差度21%-50%' }}
          </li>
          <li @click="onChangelegends(2)" :class="{gray:legendsDot[2] }">
            <i class="img icon icon-red"></i>
            {{ typeSelectIndex === 0 ? '偏差度40%以上': '偏差度50%以上' }}
          </li>
        </ul>

        <div class="content">
          <div class="left-geo">
            <ul class="typeSels">
              <li v-for="(item, index) in typeList" :key="index" @click="onChangeType(index)" :class="{ action: index === typeSelectIndex }">{{ item.itemName }}</li>
            </ul>
            <div class="proAreaSels">
              <ul :class="{ unexpend: !expends.pro }">
                <div class="name" @click="onExpends('pro')">
                  <i class="arrow-right icon"></i>
                  <i class="img icon show-active icon-pro-sel"></i>
                  <i class="img icon hide-active icon-pro"></i>

                  产品线
                </div>
                <li v-for="(item, index) in proList" :key="index" @click="onChangeProLines(index )" :class="{ active: index === proSelectIndex, disabled: index>0 && typeSelectIndex === 1 }">
                  <i class="img icon show-active icon-data-sel"></i>
                  <i class="img icon hide-active icon-data"></i>
                  {{ item.itemName }}
                </li>
              </ul>
              <ul :class="{ unexpend: !expends.area }">
                <div class="name" @click="onExpends('area')">
                  <i class="arrow-right icon"></i>
                  <i class="img icon show-active icon-area-sel"></i>
                  <i class="img icon hide-active icon-area"></i>
                  区域
                </div>
                <li v-for="(item, index) in areaList" :key="index" :class="{ active: index === areaSelIndex }">
                  <i class="img icon show-active icon-data-sel"></i>
                  <i class="img icon hide-active icon-data"></i>
                  <span style="cursor: pointer;width: 120px;" @click="onChangeArea(index )">{{ item.itemName }}</span>
                  <i class="img icon show-active icon-more-sel" style="margin-left: 10px;cursor: pointer;" @click="getData( null,'水泥配料', item.itemName)"></i>
                  <i class="img icon hide-active icon-more" style="margin-left: 10px;cursor: pointer;" @click="getData( null,'水泥配料', item.itemName)"></i>
                </li>
              </ul>
            </div>
          </div>
          <div class="echarts-content" :style="mainStyle">
            <div class="img china-map-bg"></div>
            <!--        <img src="http://10.40.0.33:9001/file-storage/487396325012760576-source.svg" class="china-map-bg" alt="" />-->
            <a-spin :spinning="loadingStatus" tip="数据正在加载...">
              <div class="echarts-main" id="echarts-chinamap"></div>
            </a-spin>
          </div>
        </div>
      </div>

      <!-- end vid_pwix3i6a8b 自定义模板_r3koyasnpg -->
      <!-- begin vid_z354kcjic1 图片_7j0nyi479u -->
      <al-image
        v-if="false"
        class="vid_z354kcjic1"
        :emptyImgSrc="''"
        :src="vid_z354kcjic1_props.src"
      />
      <!-- end vid_z354kcjic1 图片_7j0nyi479u -->
      <!-- begin vid_crznpxme1j 图片_f7l2frg8h7 -->
      <al-image
        class="vid_crznpxme1j"
        :emptyImgSrc="''"
        :src="vid_crznpxme1j_props.src"
      />
      <!-- end vid_crznpxme1j 图片_f7l2frg8h7 -->
    </a-spin>
  </div>
</template>
<script setup lang="tsx">
  import {
      h, ref, reactive, toRaw, markRaw, watch, computed,
      onBeforeMount, onMounted, onBeforeUnmount, onUnmounted, onActivated, onDeactivated
    } from "vue";
    import { useRoute, useRouter } from 'vue-router';
    const router = useRouter();
    const route = useRoute();
    import { get, post, put, del, request, requestWithHeaders } from '@/utils/http/Axios';
    import { cloneDeep, localGet, merge, getDifferenceArray, traversalTreeStructure, checkCaseCondition, renderStringInTemplate, handleBreadcrumbJump, throttle, permission, getComponentParamsValue } from '@/utils/index';
    import { isNullOrEmpty, isEmptyArr, isNullOrUnDef, isContained, isArray, isEmpty, isObject } from '@/utils/is';
    import dayjs from 'dayjs';
    import { getPagePcChartsDataSourceConvert } from '@/utils/chart';
    import { message, notification, Modal } from 'ant-design-vue'
    import { propertyFormatByNumber, propertyFormatByPercentage, propertyFormatByDate, parseSubFromDataList } from '@/utils/format';
    import colorTheme from '@/design/custom-theme.json';
    
    import UserTableRecords from '@/model/UserTableRecords';
    import { getAppBaseUrl } from '@/utils/index';
    import { sendToken } from "@/hooks/useIframeToken";
    import { useSystemStore } from "@/store/modules/system";
    const systemStore = useSystemStore();
    



      // 获取传入的流程ID和组件参数
      const props = defineProps({
            'processInstanceId': {
            type: [String,Number,Boolean],
            default: undefined,
        },
      })
      const immediateWatch = (source, callback) => {
        watch(source, callback, {deep: true,immediate: true })
      }



  /* -------------------------- 属性定义 -------------------------- */

      const setTimeOutList = [];
      const pageLoading = reactive({
        loading: false,
        tip: undefined
      });
      const authInfo = localGet('app-user-store');
// 图片 http://10.40.0.33:9001/file-storage/493887559979984896.png
import vid_z354kcjic1_imageUrl from '@/assets/images/1fbfe9e6c143987152a1e8c8d0c7a098.png'

    const vid_z354kcjic1_props = reactive({
          src: vid_z354kcjic1_imageUrl,
  })
// 图片 http://10.40.0.33:9001/file-storage/493904223171733504.png
import vid_crznpxme1j_imageUrl from '@/assets/images/71f2aa0b9331cd4bf275859992e21f52.png'

    const vid_crznpxme1j_props = reactive({
          src: vid_crznpxme1j_imageUrl,
  })



      // 处理校验
      const setSubFormName =(parentInfo, name)=>{
        return [parentInfo.parents, parentInfo.cycleIndex, name];
      }


  /* ========================== 属性定义 ========================== */


  /* -------------------------- 元素数据引用 -------------------------- */


  /* ========================== 元素数据引用 ========================== */


  /* -------------------------- 页面数据 -------------------------- */


  /* ========================== 页面数据 ========================== */



  /* -------------------------- 响应 -------------------------- */

  /* ========================== 响应 ========================== */


  /* -------------------------- 函数 -------------------------- */

  /* ========================== 函数 ========================== */


  /* -------------------------- 页面参数 -------------------------- */

    const pageParameter_state = reactive({
        'processInstanceId': props.processInstanceId ?? route.query.processInstanceId,
    })

  /* ========================== 页面参数 ========================== */


  /* -------------------------- 组件事件处理方法 -------------------------- */

    // ---------------------------- 组件数据同步 ----------------------------

    // ============================ 组件数据同步 ============================


  /* ========================== 组件事件处理方法 ========================== */


  /* -------------------------- 生命周期 -------------------------- */
  // 用于参数变更后重新执行自定义指令
      const queryUpdateFlag = ref(0);
      onMounted(() => { ;

    });

    onUnmounted(() => {
      // 销毁定时器
      setTimeOutList.forEach(({ repeat, timer }) => {
        repeat ?  clearInterval(timer): clearTimeout(timer);
      });
    });

  /* ========================== 生命周期 ========================== */


  /* -------------------------- 数据关联处理 -------------------------- */





  /* -------------------------- 表单数据同步 -------------------------- */
  /* ========================== 表单数据同步 ========================== */

  /* ========================== 数据关联处理 ========================== */


  /* -------------------------- 不同组件自定义的处理逻辑 -------------------------- */

  /* ========================== 不同组件自定义的处理逻辑 ========================== */


  // ================================定制化逻辑========================================
  import { nextTick } from 'vue'
  import * as echarts from 'echarts'
  // import chinaJson from './china'
  const chinaJson = {}
  const chartBox = ref(null)
  const loadingStatus = ref(true)
  const areaList = ref([
    // { itemName: '西南水泥', children: [{ itemName: '黑龙江省' }, { itemName: '云南省' }] },
  ])
  const proList = ref([
    // { itemName: '西南水泥', children: [{ itemName: '黑龙江省' }, { itemName: '云南省' }] },
  ])
  const dataId = ref('echarts-chinaMap')
  const proSelectIndex = ref(0)
  const areaSelIndex = ref(null)
  const typeSelectIndex = ref(0)
  const expends = ref({
    pro: true,
    area: true
  })
  const onExpends = type => {
    expends.value[type] = !expends.value[type]
    // if (type == 'pro') {
    //     proSelectIndex.value = null
    // }
    // if (type == 'area') {
    //     areaSelIndex.value = null
    // }
  }
  // 计算属性 mergeoptions
  const mergeoptions = computed(() => {
    const defaultOpt = {}
    return {
      ...defaultOpt,
      ...options.value
    }
  })

  const mainStyle = ref(document.body.offsetWidth)
  const proLineDatas = ref([])
  const typeList = ref([
    { itemName: '任务完成', type: 'TASK_DEVIATION' },
    { itemName: '资源投入', type: 'RESOURCE_DEVIATION' },
  ])
  const options = computed(() => ({
    // roam: true, // 开启鼠标缩放和平移漫游
    // zoom: 1, // 初始缩放比例
    // scaleLimit: { // 缩放的比例限制
    //     min: 1, // 最小缩放比例
    //     max: 20 // 最大缩放比例
    // },
    tooltip: {
      show: true,
      position: 'top',
      className: 'map-dialog',
      renderMode: 'html',
      formatter(params) {
        return params.data.factoryName
       // return `<div class="status-${params.data.legendsType}">${params.data.factoryName}<div class="value"><i></i>${params.data.deviation}</div></div>`
      }
    },
    grid: {
      top: 0,
      left: 0,
      right: 0,
      bottom: 0
    },
    geo: [
      {
        // top:530,
        map: 'chinaBoundary',
        // 避免边框选中，设置不响应事件
        silent: true,
        emphasis: {
          disabled: true
        },
        itemStyle: {
          normal: {
            // borderWidth: 5,
            areaColor: 'rgba(0, 0, 0, 0)',
            borderColor: 'rgba(255, 255, 255, 0)'
          }
        }
      }
    ],
    series: [
      {
        type: 'map',
        silent: true,
        selectedMode: false,
        map: 'china',
        coordinateSystem: 'geo',
        label: {
          show: true,
          color: '#333',
          fontSize: 12
        },
        itemStyle: {
          normal: {
            areaColor: 'rgba(0, 0, 0, 0)',
            borderColor: 'rgba(0, 0, 0, 0)',
            borderJoin :"round"
          },
          emphasis: {
            label: {
              show: true,
              color: '#3a76ff',
              fontSize: 12
            },
            borderWidth: 1.4,
            borderJoin :"round",
            areaColor: 'rgba(56,177,255,.1)',
            borderColor: '#3a76ff' // 设置省份分界线的颜色
          }
        }
      },

      {
        type: 'effectScatter',
        coordinateSystem: 'geo',
        data: proLineDatas.value.filter(item=> !legendsDot.value[item.legendsType]  ),
        // 标记点样式
        symbolSize: 7,
        showEffectOn: 'render'
      }
    ]
  }))

  //   初始化图表
  const initChartBox = () => {
    chartBox.value = echarts.init(document.getElementById('echarts-chinamap'), null, {
      renderer: 'svg',
      devicePixelRatio: 2
    })
    window.addEventListener('resize', () => {
      setMainStyle()
      chartBox.value?.resize()
    })
    renderChart()
    chartBox.value.on('click', bindMapClik)
  }

  //   绑定点击
  const bindMapClik = params => {
    if (params.componentType === 'series' && params.data) {
      const data = params.data
      getData(data.projectId, proList.value[proSelectIndex.value].itemName)
    }
  }

  //   渲染
  const renderChart = () => {
    if (!chartBox.value) {
      initChartBox()
      chartBox.value?.setOption(mergeoptions.value)
    } else {
      chartBox.value?.setOption(mergeoptions.value)
    }
  }

  // 切换分类
  const onChangeType = index => {
    if (index === typeSelectIndex.value) return
    typeSelectIndex.value = index
    proSelectIndex.value = 0
    onGetProDatas()
  }
  //切换产线
  const onChangeProLines = (index,type) => {
    if( index>0 && typeSelectIndex.value === 1 ) {
      return
    }
    proSelectIndex.value = index
     areaSelIndex.value = null
    expends.value.pro = true
    onGetProDatas()
  }

  // 切换区域
  const onChangeArea = index => {
    expends.value.area = true
    toogleHighlight('downplay', areaSelIndex.value || 0)
    nextTick(() => {
      areaSelIndex.value = index
      toogleHighlight('highlight', index)
    })
  }


  // 切换区域
  const legendsDot = ref([false,false,false])
  const onChangelegends = index => {
    legendsDot.value[index] = !legendsDot.value[index]
    renderChart()
  }


  //   切换区域
  const toogleHighlight = (type = 'highlight', index) => {
    const area = areaList.value[index]
    area.children.forEach(item => {
      const name = item.itemName.replace(/[省市自治区]/g, '')
      chartBox.value?.dispatchAction({
        type,
        name: name
      })
    })
  }

  //
  const ongetoperation = params => {
    loadingStatus.value = true
    post('/solution-ppm/api/v2/built-in-system-ppm/project/dashboard/operation/search', params)
      .then(res => {
        const colors = ['#52c41a', '#ffc500', '#f5222d']
        proLineDatas.value = res.data?.map(item => {
          const index = Number(item.deviation) < 21 ? 0 : Number(item.deviation) > 50 ? 2 : 1
          return {
            ...item,
            value: [item.longuide, item.latitude],
            itemStyle: {
              color: colors[index]
            },
            rippleEffect: {
              brushType: 'fill',
              scale: 3,
              number: 2,
              period: 3,
              color: colors[index]
            },
            legendsType:index
          }
        })
        renderChart()
        loadingStatus.value = false
      })
      .catch(error => {
        console.error('失败:', error)
      })
  }

  const onGetProDatas = () => {
    ongetoperation({
      productLine: proList.value[proSelectIndex.value].itemName,
      type: typeList.value[typeSelectIndex.value].type
    })
  }

  const onGetChinaJson = async params => {
    if (sessionStorage.getItem('chinaMapJson')) {
      return JSON.parse(sessionStorage.getItem('chinaMapJson'))
    }
    const res = await get('/solution-ppm/api/v2/built-in-system-ppm/project/dashboard/operation/china')
    sessionStorage.setItem('chinaMapJson', res.data)
    return JSON.parse(res.data)
  }

  const onAreaList = params => {
    if (sessionStorage.getItem('onAreaList')) {
      return JSON.parse(sessionStorage.getItem('onAreaList'))
    }
    get('/solution-ppm/api/v2/built-in-system-ppm/dictionary/search_tree/OPERATION.AREA')
      .then(res => {
        areaList.value = res.data || []
        sessionStorage.setItem('areaList', JSON.stringify(res.data))
      })
      .catch(error => {
        console.error('失败:', error)
      })
  }

  const getProList = params => {
    get('/solution-ppm/api/v2/built-in-system-ppm/dictionary/search/OPERATION.PRODUCT_LINE')
      .then(res => {
        proList.value = res.data || []
        if (res.data && res.data[0]) {
          onChangeProLines(0)
        }
      })
      .catch(error => {
        console.error('失败:', error)
      })
  }

  const init = async () => {
    setMainStyle()
    const chinaJsonData = (await onGetChinaJson()) || chinaJson
    echarts.registerMap('china', chinaJsonData)
    echarts.registerMap('chinaBoundary', chinaJsonData)
    initChartBox()
    onAreaList()
    getProList()
  }

  onMounted(() => {
    init()
  })
  const setMainStyle = () => {
      const dom = document.getElementById('mainContent')
    let cliWidth =dom.offsetWidth;
    let cliHeight =dom.offsetHeight;
    let contW = 1126 ;
    let contH = 851;
    let w = cliWidth / contW;
    let h = cliHeight / contH;
    let per = w < h ? w : h;
     mainStyle.value = `transform: scale(${per*1.15} , ${per*1.15 * 0.89});transform-origin:center;margin-top:${contH*(per-1)/2}px;`
  }

  onBeforeUnmount(() => {
    if (chartBox.value) {
      chartBox.value.dispose()
      chartBox.value = null
      window.removeEventListener('resize', () => {
        chartBox.value?.resize()
      })
    }
  })

  const watchMergeOptions = watch(
    mergeoptions,
    () => {
      renderChart()
    },
    { deep: true }
  )

  // 暴露给模板的变量和函数
  defineExpose({
    areaList,
    areaSelIndex,
    onChangeArea,
    toogleHighlight
  })
  // 里程碑进度表弹窗
  // 里程碑进度表弹窗
  // 里程碑进度表弹窗
  // 里程碑进度表弹窗
  // 里程碑进度表弹窗
  const filteredColumns = computed(() => {
    return columnState.columns
      .map(column => {
        const updatedColumn = {
          ...column,
          children:
            column.children && Array.isArray(column.children)
              ? column.children.filter(child => child.visible)
              : []
        }

        if (updatedColumn.children.length === 0 && column.children?.length > 0) {
          updatedColumn.visible = false
        }

        return updatedColumn.visible === false ? null : updatedColumn
      })
      .filter(Boolean)
  })
  const overStyle = ref({
    maxWidth: '300px',
    fontSize: '16px'
  })
  const customOkCellStyle = () => {
    return {
      style: {
        padding: '4px 16px'
      }
    }
  }
  const handleResizeColumn = (w, col) => {
    const width = w - 50 // 确保宽度被计算并且减去额外空间

    // 根据列标题来确定不同的 div
    let div = null
    if (col.title === '进展') {
      div = document.querySelectorAll('.omit-div')
    } else if (col.title.includes('问题&风险')) {
      div = document.querySelectorAll('.omit-div-question')
    } else if (col.title === '生产计划') {
      div = document.querySelectorAll('.omit-div-productionPlan')
    } else if (col.title === '客情关系') {
      div = document.querySelectorAll('.omit-div-customerRelationship')
    }

    // 如果找到了对应的 div，更新其宽度
    if (div.length > 0) {
      div.forEach(item => {
        item.style.width = `${width}px`
      })
      overStyle.value.maxWidth = `${width}px` // 更新 tooltip 最大宽度
    }

    // 更新 columnState 中的列宽
    columnState.columns = columnState.columns.map(item => {
      if (item.dataIndex === col.dataIndex) {
        return { ...item, width: w } // 更新该列的宽度
      }
      return item
    })

    // 如果列有子列，确保子列也能根据父列的宽度进行更新
    if (col.children) {
      col.children.forEach(child => {
        columnState.columns = columnState.columns.map(item => {
          if (item.dataIndex === child.dataIndex) {
            return { ...item, width: w } // 更新子列的宽度
          }
          return item
        })
      })
    }
  }
  const columnState = reactive({
    columns: [
      {
        title: '序号',
        dataIndex: 'count',
        align: 'center',
        width: 50,
        fixed: 'left',
        ellipsis: true
      },
      {
        'title': '区域',
        'dataIndex': 'areaName',
        ellipsis: true,
        width: 120,
        fixed: 'left',
        align: 'center'
      },
      {
        title: '工厂名称',
        dataIndex: 'projectShortName',
        ellipsis: true,
        width: 130,
        fixed: 'left',
        align: 'center'
      },

      {
        title: '批次',
        dataIndex: 'batch',
        ellipsis: true,
        width: 80,
        align: 'center',
        visible: computed(() => ['全部', '基础信息'].includes(ftfState.radioValue))
      },

      {
        title: '产品类型',
        dataIndex: 'productType',
        ellipsis: true,
        width: 80,
        align: 'center',
        visible: computed(() => ['全部', '基础信息'].includes(ftfState.radioValue))
      },
      {
        title: '项目总监',
        dataIndex: 'projectDirector',
        ellipsis: true,
        align: 'center',
        width: 80,
        visible: computed(() => ['全部', '基础信息'].includes(ftfState.radioValue))
      },
      {
        title: '水泥专家',
        dataIndex: 'businessExpert',
        align: 'center',
        ellipsis: true,
        width: 80,
        visible: computed(() => ['全部', '基础信息'].includes(ftfState.radioValue))
      },
      {
        title: '项目经理',
        dataIndex: 'pmName',
        align: 'center',
        ellipsis: true,
        width: 80,
        customCell: customOkCellStyle,
        visible: computed(() => ['全部', '基础信息'].includes(ftfState.radioValue))
      },
      {
        title: '算法',
        dataIndex: 'algorithmExpert',
        align: 'center',
        ellipsis: true,
        width: 80,
        customCell: customOkCellStyle,
        visible: computed(() => ['全部', '基础信息'].includes(ftfState.radioValue))
      },
      {
        title: '商务',
        dataIndex: 'preSaleManager',
        align: 'center',
        ellipsis: true,
        width: 80,
        customCell: customOkCellStyle,
        visible: computed(() => ['全部', '基础信息'].includes(ftfState.radioValue))
      },

      {
        title: '数据积累',
        ellipsis: true,
        align: 'center',
        visible: computed(() => ['全部', '项目阶段'].includes(ftfState.radioValue)),
        children: [
          {
            title: '计划开始',
            dataIndex: 'collectionMappingPlanStartTime',
            ellipsis: true,
            align: 'center',
            width: 150,
            sorter: (a, b) => {
              const timeA = dayjs(a.collectionMappingPlanStartTime)
              const timeB = dayjs(b.collectionMappingPlanStartTime)

              // 处理空值，确保空值排在最后
              if (!timeA.isValid() && !timeB.isValid()) return 0
              if (!timeA.isValid()) return 1 // a 是无效时间，排到后面
              if (!timeB.isValid()) return -1 // b 是无效时间，排到后面

              // 有效的时间做正常排序
              return timeA - timeB
            },
            visible: true
          },
          {
            title: '计划结束',
            dataIndex: 'collectionMappingPlanEndTime',
            ellipsis: true,
            align: 'center',
            width: 150,
            sorter: (a, b) => {
              const timeA = dayjs(a.collectionMappingPlanEndTime)
              const timeB = dayjs(b.collectionMappingPlanEndTime)

              if (!timeA.isValid() && !timeB.isValid()) return 0
              if (!timeA.isValid()) return 1
              if (!timeB.isValid()) return -1

              return timeA - timeB
            },
            visible: true
          },
          {
            title: '实际开始',
            dataIndex: 'collectionMappingActualStartTime',
            ellipsis: true,
            align: 'center',
            width: 150,
            sorter: (a, b) => {
              const timeA = dayjs(a.collectionMappingActualStartTime)
              const timeB = dayjs(b.collectionMappingActualStartTime)

              if (!timeA.isValid() && !timeB.isValid()) return 0
              if (!timeA.isValid()) return 1
              if (!timeB.isValid()) return -1

              return timeA - timeB
            },
            visible: true
          },

          {
            title: '实际结束',
            dataIndex: 'collectionMappingActualEndTime',
            ellipsis: true,
            align: 'center',
            width: 150,
            sorter: (a, b) => {
              const timeA = dayjs(a.collectionMappingActualEndTime)
              const timeB = dayjs(b.collectionMappingActualEndTime)

              if (!timeA.isValid() && !timeB.isValid()) return 0
              if (!timeA.isValid()) return 1
              if (!timeB.isValid()) return -1

              return timeA - timeB
            },
            visible: true
          },
          {
            title: '预计开始',
            dataIndex: 'collectionMappingExpectStartTime',
            ellipsis: true,
            align: 'center',
            width: 150,
            sorter: (a, b) => {
              const timeA = dayjs(a.collectionMappingExpectStartTime)
              const timeB = dayjs(b.collectionMappingExpectStartTime)

              if (!timeA.isValid() && !timeB.isValid()) return 0
              if (!timeA.isValid()) return 1
              if (!timeB.isValid()) return -1

              return timeA - timeB
            },
            visible: true
          },
          {
            title: '预计结束',
            dataIndex: 'collectionMappingExpectEndTime',
            ellipsis: true,
            align: 'center',
            width: 150,
            sorter: (a, b) => {
              const timeA = dayjs(a.collectionMappingExpectEndTime)
              const timeB = dayjs(b.collectionMappingExpectEndTime)

              if (!timeA.isValid() && !timeB.isValid()) return 0
              if (!timeA.isValid()) return 1
              if (!timeB.isValid()) return -1

              return timeA - timeB
            },
            visible: true
          }
        ]
      },

      {
        title: '自学习表数据确认',
        ellipsis: true,
        align: 'center',
        visible: computed(() => ['全部', '项目阶段'].includes(ftfState.radioValue)),
        children: [
          {
            title: '计划开始',
            dataIndex: 'processingTableConfirmPlanStartTime',
            ellipsis: true,
            align: 'center',
            width: 150,
            sorter: (a, b) => {
              const timeA = dayjs(a.processingTableConfirmPlanStartTime)
              const timeB = dayjs(b.processingTableConfirmPlanStartTime)

              // 处理空值，确保空值排在最后
              if (!timeA.isValid() && !timeB.isValid()) return 0
              if (!timeA.isValid()) return 1 // a 是无效时间，排到后面
              if (!timeB.isValid()) return -1 // b 是无效时间，排到后面

              // 有效的时间做正常排序
              return timeA - timeB
            },
            visible: true
          },
          {
            title: '计划结束',
            dataIndex: 'processingTableConfirmPlanEndTime',
            ellipsis: true,
            align: 'center',
            width: 150,
            sorter: (a, b) => {
              const timeA = dayjs(a.processingTableConfirmPlanEndTime)
              const timeB = dayjs(b.processingTableConfirmPlanEndTime)

              if (!timeA.isValid() && !timeB.isValid()) return 0
              if (!timeA.isValid()) return 1
              if (!timeB.isValid()) return -1

              return timeA - timeB
            },
            visible: true
          },
          {
            title: '实际开始',
            dataIndex: 'processingTableConfirmActualStartTime',
            ellipsis: true,
            align: 'center',
            width: 150,
            sorter: (a, b) => {
              const timeA = dayjs(a.processingTableConfirmActualStartTime)
              const timeB = dayjs(b.processingTableConfirmActualStartTime)

              if (!timeA.isValid() && !timeB.isValid()) return 0
              if (!timeA.isValid()) return 1
              if (!timeB.isValid()) return -1

              return timeA - timeB
            },
            visible: true
          },

          {
            title: '实际结束',
            dataIndex: 'processingTableConfirmActualEndTime',
            ellipsis: true,
            align: 'center',
            width: 150,
            sorter: (a, b) => {
              const timeA = dayjs(a.processingTableConfirmActualEndTime)
              const timeB = dayjs(b.processingTableConfirmActualEndTime)

              if (!timeA.isValid() && !timeB.isValid()) return 0
              if (!timeA.isValid()) return 1
              if (!timeB.isValid()) return -1

              return timeA - timeB
            },
            visible: true
          },
          {
            title: '预计开始',
            dataIndex: 'processingTableConfirmExpectStartTime',
            ellipsis: true,
            align: 'center',
            width: 150,
            sorter: (a, b) => {
              const timeA = dayjs(a.processingTableConfirmExpectStartTime)
              const timeB = dayjs(b.processingTableConfirmExpectStartTime)

              if (!timeA.isValid() && !timeB.isValid()) return 0
              if (!timeA.isValid()) return 1
              if (!timeB.isValid()) return -1

              return timeA - timeB
            },
            visible: true
          },
          {
            title: '预计结束',
            dataIndex: 'processingTableConfirmExpectEndTime',
            ellipsis: true,
            align: 'center',
            width: 150,
            sorter: (a, b) => {
              const timeA = dayjs(a.processingTableConfirmExpectEndTime)
              const timeB = dayjs(b.processingTableConfirmExpectEndTime)

              if (!timeA.isValid() && !timeB.isValid()) return 0
              if (!timeA.isValid()) return 1
              if (!timeB.isValid()) return -1

              return timeA - timeB
            },
            visible: true
          }
        ]
      },
      {
        title: '数据建模',
        ellipsis: true,
        align: 'center',
        visible: computed(() => ['全部', '项目阶段'].includes(ftfState.radioValue)),
        children: [
          {
            title: '计划开始',
            dataIndex: 'modelStartTime',
            ellipsis: true,
            align: 'center',
            width: 150,
            sorter: (a, b) => {
              const timeA = dayjs(a.modelStartTime)
              const timeB = dayjs(b.modelStartTime)

              // 处理空值，确保空值排在最后
              if (!timeA.isValid() && !timeB.isValid()) return 0
              if (!timeA.isValid()) return 1 // a 是无效时间，排到后面
              if (!timeB.isValid()) return -1 // b 是无效时间，排到后面

              // 有效的时间做正常排序
              return timeA - timeB
            },
            visible: true
          },
          {
            title: '计划结束',
            dataIndex: 'modelEndTime',
            ellipsis: true,
            align: 'center',
            width: 150,
            sorter: (a, b) => {
              const timeA = dayjs(a.modelEndTime)
              const timeB = dayjs(b.modelEndTime)

              if (!timeA.isValid() && !timeB.isValid()) return 0
              if (!timeA.isValid()) return 1
              if (!timeB.isValid()) return -1

              return timeA - timeB
            },
            visible: true
          },
          {
            title: '实际开始',
            dataIndex: 'modelActualStartTime',
            ellipsis: true,
            align: 'center',
            width: 150,
            sorter: (a, b) => {
              const timeA = dayjs(a.modelActualStartTime)
              const timeB = dayjs(b.modelActualStartTime)

              if (!timeA.isValid() && !timeB.isValid()) return 0
              if (!timeA.isValid()) return 1
              if (!timeB.isValid()) return -1

              return timeA - timeB
            },
            visible: true
          },

          {
            title: '实际结束',
            dataIndex: 'modelActualEndTime',
            ellipsis: true,
            align: 'center',
            width: 150,
            sorter: (a, b) => {
              const timeA = dayjs(a.modelActualEndTime)
              const timeB = dayjs(b.modelActualEndTime)

              if (!timeA.isValid() && !timeB.isValid()) return 0
              if (!timeA.isValid()) return 1
              if (!timeB.isValid()) return -1

              return timeA - timeB
            },
            visible: true
          },
          {
            title: '预计开始',
            dataIndex: 'modelExpectStartTime',
            ellipsis: true,
            align: 'center',
            width: 150,
            sorter: (a, b) => {
              const timeA = dayjs(a.modelExpectStartTime)
              const timeB = dayjs(b.modelExpectStartTime)

              if (!timeA.isValid() && !timeB.isValid()) return 0
              if (!timeA.isValid()) return 1
              if (!timeB.isValid()) return -1

              return timeA - timeB
            },
            visible: true
          },
          {
            title: '预计结束',
            dataIndex: 'modelExpectEndTime',
            ellipsis: true,
            align: 'center',
            width: 150,
            sorter: (a, b) => {
              const timeA = dayjs(a.modelExpectEndTime)
              const timeB = dayjs(b.modelExpectEndTime)

              if (!timeA.isValid() && !timeB.isValid()) return 0
              if (!timeA.isValid()) return 1
              if (!timeB.isValid()) return -1

              return timeA - timeB
            },
            visible: true
          }
        ]
      },
      {
        title: '试运行',
        ellipsis: true,
        align: 'center',
        visible: computed(() => ['全部', '项目阶段'].includes(ftfState.radioValue)),
        children: [
          {
            title: '计划开始',
            dataIndex: 'testRunStartTime',
            ellipsis: true,
            align: 'center',
            width: 150,
            sorter: (a, b) => {
              const timeA = dayjs(a.testRunStartTime)
              const timeB = dayjs(b.testRunStartTime)

              if (!timeA.isValid() && !timeB.isValid()) return 0
              if (!timeA.isValid()) return 1
              if (!timeB.isValid()) return -1

              return timeA - timeB
            },
            visible: true
          },

          {
            title: '计划结束',
            dataIndex: 'testRunEndTime',
            ellipsis: true,
            align: 'center',
            width: 150,
            sorter: (a, b) => {
              const timeA = dayjs(a.testRunEndTime)
              const timeB = dayjs(b.testRunEndTime)

              if (!timeA.isValid() && !timeB.isValid()) return 0
              if (!timeA.isValid()) return 1
              if (!timeB.isValid()) return -1

              return timeA - timeB
            },
            visible: true
          },
          {
            title: '实际开始',
            dataIndex: 'testRunActualStartTime',
            ellipsis: true,
            align: 'center',
            width: 150,
            sorter: (a, b) => {
              const timeA = dayjs(a.testRunActualStartTime)
              const timeB = dayjs(b.testRunActualStartTime)

              if (!timeA.isValid() && !timeB.isValid()) return 0
              if (!timeA.isValid()) return 1
              if (!timeB.isValid()) return -1

              return timeA - timeB
            },
            visible: true
          },
          {
            title: '实际结束',
            dataIndex: 'testRunActualEndTime',
            ellipsis: true,
            align: 'center',
            width: 150,
            sorter: (a, b) => {
              const timeA = dayjs(a.testRunActualEndTime)
              const timeB = dayjs(b.testRunActualEndTime)

              if (!timeA.isValid() && !timeB.isValid()) return 0
              if (!timeA.isValid()) return 1
              if (!timeB.isValid()) return -1

              return timeA - timeB
            },
            visible: true
          },
          {
            title: '预计开始',
            dataIndex: 'testRunExpectStartTime',
            ellipsis: true,
            align: 'center',
            width: 150,
            sorter: (a, b) => {
              const timeA = dayjs(a.testRunExpectStartTime)
              const timeB = dayjs(b.testRunExpectStartTime)

              if (!timeA.isValid() && !timeB.isValid()) return 0
              if (!timeA.isValid()) return 1
              if (!timeB.isValid()) return -1

              return timeA - timeB
            },
            visible: true
          },
          {
            title: '预计结束',
            dataIndex: 'testRunExpectEndTime',
            ellipsis: true,
            align: 'center',
            width: 150,
            sorter: (a, b) => {
              const timeA = dayjs(a.testRunExpectEndTime)
              const timeB = dayjs(b.testRunExpectEndTime)

              if (!timeA.isValid() && !timeB.isValid()) return 0
              if (!timeA.isValid()) return 1
              if (!timeB.isValid()) return -1

              return timeA - timeB
            },
            visible: true
          }
        ]
      },
      {
        title: '正式运行',
        ellipsis: true,
        align: 'center',
        visible: computed(() => ['全部', '项目阶段'].includes(ftfState.radioValue)),
        children: [
          {
            title: '计划开始',
            dataIndex: 'runStartTime',
            ellipsis: true,
            align: 'center',
            width: 150,
            sorter: (a, b) => {
              const timeA = dayjs(a.runStartTime)
              const timeB = dayjs(b.runStartTime)

              if (!timeA.isValid() && !timeB.isValid()) return 0
              if (!timeA.isValid()) return 1
              if (!timeB.isValid()) return -1

              return timeA - timeB
            },
            visible: true
          },

          {
            title: '计划结束',
            dataIndex: 'runEndTime',
            ellipsis: true,
            align: 'center',
            width: 150,
            sorter: (a, b) => {
              const timeA = dayjs(a.runEndTime)
              const timeB = dayjs(b.runEndTime)

              if (!timeA.isValid() && !timeB.isValid()) return 0
              if (!timeA.isValid()) return 1
              if (!timeB.isValid()) return -1

              return timeA - timeB
            },
            visible: true
          },
          {
            title: '实际开始',
            dataIndex: 'runActualStartTime',
            ellipsis: true,
            align: 'center',
            width: 150,
            sorter: (a, b) => {
              const timeA = dayjs(a.runActualStartTime)
              const timeB = dayjs(b.runActualStartTime)

              if (!timeA.isValid() && !timeB.isValid()) return 0
              if (!timeA.isValid()) return 1
              if (!timeB.isValid()) return -1

              return timeA - timeB
            },
            visible: true
          },
          {
            title: '实际结束',
            dataIndex: 'runActualEndTime',
            ellipsis: true,
            align: 'center',
            width: 150,
            sorter: (a, b) => {
              const timeA = dayjs(a.runActualEndTime)
              const timeB = dayjs(b.runActualEndTime)

              if (!timeA.isValid() && !timeB.isValid()) return 0
              if (!timeA.isValid()) return 1
              if (!timeB.isValid()) return -1

              return timeA - timeB
            },
            visible: true
          },
          {
            title: '预计开始',
            dataIndex: 'runExpectStartTime',
            ellipsis: true,
            align: 'center',
            width: 150,
            sorter: (a, b) => {
              const timeA = dayjs(a.runExpectStartTime)
              const timeB = dayjs(b.runExpectStartTime)

              if (!timeA.isValid() && !timeB.isValid()) return 0
              if (!timeA.isValid()) return 1
              if (!timeB.isValid()) return -1

              return timeA - timeB
            },
            visible: true
          },
          {
            title: '预计结束',
            dataIndex: 'runExpectEndTime',
            ellipsis: true,
            align: 'center',
            width: 150,
            sorter: (a, b) => {
              const timeA = dayjs(a.runExpectEndTime)
              const timeB = dayjs(b.runExpectEndTime)

              if (!timeA.isValid() && !timeB.isValid()) return 0
              if (!timeA.isValid()) return 1
              if (!timeB.isValid()) return -1

              return timeA - timeB
            },
            visible: true
          }
        ]
      },
      {
        title: '验证',
        ellipsis: true,
        align: 'center',
        visible: computed(() => ['全部', '项目阶段'].includes(ftfState.radioValue)),
        children: [
          {
            title: '计划开始',
            dataIndex: 'verifyStartTime',
            ellipsis: true,
            align: 'center',
            width: 150,
            sorter: (a, b) => {
              const timeA = dayjs(a.verifyStartTime)
              const timeB = dayjs(b.verifyStartTime)

              if (!timeA.isValid() && !timeB.isValid()) return 0
              if (!timeA.isValid()) return 1
              if (!timeB.isValid()) return -1

              return timeA - timeB
            },
            visible: true
          },

          {
            title: '计划结束',
            dataIndex: 'verifyEndTime',
            ellipsis: true,
            align: 'center',
            width: 150,
            sorter: (a, b) => {
              const timeA = dayjs(a.verifyEndTime)
              const timeB = dayjs(b.verifyEndTime)

              if (!timeA.isValid() && !timeB.isValid()) return 0
              if (!timeA.isValid()) return 1
              if (!timeB.isValid()) return -1

              return timeA - timeB
            },
            visible: true
          },
          {
            title: '实际开始',
            dataIndex: 'verifyActualStartTime',
            ellipsis: true,
            align: 'center',
            width: 150,
            sorter: (a, b) => {
              const timeA = dayjs(a.verifyActualStartTime)
              const timeB = dayjs(b.verifyActualStartTime)

              if (!timeA.isValid() && !timeB.isValid()) return 0
              if (!timeA.isValid()) return 1
              if (!timeB.isValid()) return -1

              return timeA - timeB
            },
            visible: true
          },
          {
            title: '实际结束',
            dataIndex: 'verifyActualEndTime',
            ellipsis: true,
            align: 'center',
            width: 150,
            sorter: (a, b) => {
              const timeA = dayjs(a.verifyActualEndTime)
              const timeB = dayjs(b.verifyActualEndTime)

              if (!timeA.isValid() && !timeB.isValid()) return 0
              if (!timeA.isValid()) return 1
              if (!timeB.isValid()) return -1

              return timeA - timeB
            },
            visible: true
          },
          {
            title: '预计开始',
            dataIndex: 'verifyExpectStartTime',
            ellipsis: true,
            align: 'center',
            width: 150,
            sorter: (a, b) => {
              const timeA = dayjs(a.verifyExpectStartTime)
              const timeB = dayjs(b.verifyExpectStartTime)

              if (!timeA.isValid() && !timeB.isValid()) return 0
              if (!timeA.isValid()) return 1
              if (!timeB.isValid()) return -1

              return timeA - timeB
            },
            visible: true
          },
          {
            title: '预计结束',
            dataIndex: 'verifyExpectEndTime',
            ellipsis: true,
            align: 'center',
            width: 150,
            sorter: (a, b) => {
              const timeA = dayjs(a.verifyExpectEndTime)
              const timeB = dayjs(b.verifyExpectEndTime)

              if (!timeA.isValid() && !timeB.isValid()) return 0
              if (!timeA.isValid()) return 1
              if (!timeB.isValid()) return -1

              return timeA - timeB
            },
            visible: true
          }
        ]
      },
      {
        title: '验收',
        ellipsis: true,
        align: 'center',
        visible: computed(() => ['全部', '项目阶段'].includes(ftfState.radioValue)),
        children: [
          {
            title: '计划开始',
            dataIndex: 'checkStartTime',
            ellipsis: true,
            align: 'center',
            width: 150,
            sorter: (a, b) => {
              const timeA = dayjs(a.checkStartTime)
              const timeB = dayjs(b.checkStartTime)

              if (!timeA.isValid() && !timeB.isValid()) return 0
              if (!timeA.isValid()) return 1
              if (!timeB.isValid()) return -1

              return timeA - timeB
            },
            visible: true
          },

          {
            title: '计划结束',
            dataIndex: 'checkEndTime',
            ellipsis: true,
            align: 'center',
            width: 150,
            sorter: (a, b) => {
              const timeA = dayjs(a.checkEndTime)
              const timeB = dayjs(b.checkEndTime)

              if (!timeA.isValid() && !timeB.isValid()) return 0
              if (!timeA.isValid()) return 1
              if (!timeB.isValid()) return -1

              return timeA - timeB
            },
            visible: true
          },
          {
            title: '实际开始',
            dataIndex: 'checkActualStartTime',
            ellipsis: true,
            align: 'center',
            width: 150,
            sorter: (a, b) => {
              const timeA = dayjs(a.checkActualStartTime)
              const timeB = dayjs(b.checkActualStartTime)

              if (!timeA.isValid() && !timeB.isValid()) return 0
              if (!timeA.isValid()) return 1
              if (!timeB.isValid()) return -1

              return timeA - timeB
            },
            visible: true
          },
          {
            title: '实际结束',
            dataIndex: 'checkActualEndTime',
            ellipsis: true,
            align: 'center',
            width: 150,
            sorter: (a, b) => {
              const timeA = dayjs(a.checkActualEndTime)
              const timeB = dayjs(b.checkActualEndTime)

              if (!timeA.isValid() && !timeB.isValid()) return 0
              if (!timeA.isValid()) return 1
              if (!timeB.isValid()) return -1

              return timeA - timeB
            },
            visible: true
          },
          {
            title: '预计开始',
            dataIndex: 'checkExpectStartTime',
            ellipsis: true,
            align: 'center',
            width: 150,
            sorter: (a, b) => {
              const timeA = dayjs(a.checkExpectStartTime)
              const timeB = dayjs(b.checkExpectStartTime)

              if (!timeA.isValid() && !timeB.isValid()) return 0
              if (!timeA.isValid()) return 1
              if (!timeB.isValid()) return -1

              return timeA - timeB
            },
            visible: true
          },
          {
            title: '预计结束',
            dataIndex: 'checkExpectEndTime',
            ellipsis: true,
            align: 'center',
            width: 150,
            sorter: (a, b) => {
              const timeA = dayjs(a.checkExpectEndTime)
              const timeB = dayjs(b.checkExpectEndTime)

              if (!timeA.isValid() && !timeB.isValid()) return 0
              if (!timeA.isValid()) return 1
              if (!timeB.isValid()) return -1

              return timeA - timeB
            },
            visible: true
          }
        ]
      },

      {
        title: '项目阶段',
        dataIndex: 'milepostName',
        sorter: true,
        ellipsis: true,
        align: 'center',
        width: 80,
        sorter: true,
        visible: computed(() => ['全部', '基础信息'].includes(ftfState.radioValue))
      },
      {
        title: '项目状态',
        dataIndex: 'projectStatus',
        ellipsis: true,
        align: 'center',
        width: 80,
        visible: computed(() => ['全部', '基础信息'].includes(ftfState.radioValue))
      },
      {
        title: '进展',
        dataIndex: 'progress',
        ellipsis: true,
        resizable: true,
        align: 'center',
        width: 350,
        minWidth: 350,
        visible: computed(() => ['全部', '其他'].includes(ftfState.radioValue))
      },

      {
        title: '问题&风险',
        dataIndex: 'question',
        ellipsis: true,
        align: 'center',
        resizable: true,
        width: 350,
        minWidth: 350,
        visible: computed(() => ['全部', '其他'].includes(ftfState.radioValue))
      },
      {
        title: '风险等级',
        dataIndex: 'riskLevel',
        align: 'center',
        ellipsis: true,
        width: 120,
        visible: computed(() => ['全部', '其他'].includes(ftfState.radioValue))
      },
      {
        title: '项目支持',
        dataIndex: 'supportors',
        align: 'center',
        ellipsis: true,
        width: 120,
        visible: computed(() => ['全部', '其他'].includes(ftfState.radioValue))
      },
      {
        title: '正式运行持续天数',
        dataIndex: 'runDays',
        align: 'center',
        ellipsis: true,
        width: 120,
        visible: computed(() => ['全部', '其他'].includes(ftfState.radioValue))
      },
      {
        title: '综合样20次',
        dataIndex: 'comprehensiveSample',
        align: 'center',
        ellipsis: true,
        width: 120,
        visible: computed(() => ['全部', '其他'].includes(ftfState.radioValue))
      },
      {
        title: '降本空间',
        dataIndex: 'expectedCostReduction',
        align: 'center',
        ellipsis: true,
        width: 120,
        visible: computed(() => ['全部', '其他'].includes(ftfState.radioValue))
      },
      {
        title: '生产计划',
        dataIndex: 'productionPlan',
        resizable: true,
        align: 'center',
        ellipsis: true,
        width: 350,
        minWidth: 350,
        visible: computed(() => ['全部', '其他'].includes(ftfState.radioValue))
      },
      {
        title: '客情关系',
        dataIndex: 'customerRelationship',
        resizable: true,
        align: 'center',
        ellipsis: true,
        width: 350,
        minWidth: 350,
        visible: computed(() => ['全部', '其他'].includes(ftfState.radioValue))
      }
      // 其他通用列
    ],
    oldColumns: []
  })
  const ftfState = reactive({
    modalVisible: false,
    radioValue: '全部',
    dataSource: [],
    tableLoading: false,
    num: {
      total: undefined,
      ys: undefined,
      yswc: undefined,
      yz: undefined,
      zzyx: undefined,
      sys: undefined,
      jm: undefined,
      sjjl: undefined,
      sjcjzl: undefined
    },
    filter: {
      areaName: undefined,
      projectDirector: undefined,
      projectId: undefined,
      batch: undefined,
      milepostName: undefined,
      riskLevel: [],
      projectStatus: undefined,
      customSort: {
        'sortDirection': 'ASC',
        'filed': 'AREA'
      }
      // milepostOrder: false
    },
    checkList: ['计划开始', '计划结束', '实际开始', '实际结束', '预计开始', '预计结束'],
    baseCheckList: ['批次', '产品类型', '项目总监', '水泥专家', '项目经理', '算法', '商务', '项目阶段', '项目状态'],
    milepostCheckList: [],
    // milepostCheckList: ['验收', '验证', '正式运行', '试运行', '数据建模', '自学习表数据确认', '数据积累'],
    otherCheckList: [
      '进展',
      '问题风险',
      '风险等级',
      '项目支持',
      '正式运行持续天数',
      '综合样20次',
      '降本空间',
      '生产计划',
      '客情关系'
    ],
    settingVisible: false,
    activeKey: '基础信息'
  })
  const handleTableChange = (pagination, filters, sorter) => {
    let currentSortDirection = 'ASC' // 默认排序方向为 ASC
    let currentField = 'AREA' // 默认字段为 AREA

    if (sorter.column && sorter.column.dataIndex === 'milepostName') {
      // 判断排序方向
      if (sorter.order === 'ascend') {
        currentSortDirection = 'ASC'
      } else if (sorter.order === 'descend') {
        currentSortDirection = 'DESC'
      }
      // 设置自定义排序
      ftfState.customSort = {
        sortDirection: currentSortDirection,
        filed: 'MILEPOST' // 根据需要修改字段名
      }
    } else {
      // 如果没有对 'milepostName' 进行排序，使用默认排序
      ftfState.customSort = {
        sortDirection: currentSortDirection,
        filed: currentField
      }
    }
    getData()
  }
  function getColumns() {
    get('/solution-ppm/api/v2/built-in-system-ppm/data_collect/display_metadata').then(data => {
      if (data.code !== 200) {
        message.error(data.message)
        return
      }
      const columnList = data.data.filter(item => item.isDisplay === 'Y')
      columnState.columns = [
        ...columnState.columns,
        ...columnList.map(item => ({
          ...item,
          dataIndex: item.englishName,
          title: item.chinessName,
          width: 300,
          visible: true,
          align: 'center'
        }))
      ]
      columnState.oldColumns = data.data.map(item => {
        return {
          name: item.chinessName
        }
      })
    })
  }
  function getData(id, type, areaName) {
      if (type !== '水泥配料') {
        return
      }
      ftfState.filter.projectId = id
      ftfState.tableLoading = true
      post('/solution-ppm/api/v2/built-in-system-ppm/project_progress/search ', {
        ...ftfState.filter,
        areaName: (!id) ? [ areaName ] : null,
        customSort: ftfState.customSort
      })
      .then(data => {
        if (data.code !== 200) {
          ftfState.dataSource = []
          message.error(data.message)
          return
        }

        ftfState.dataSource = data.data.map(({ customDataMap, ...rest }) => ({
          ...rest,
          ...customDataMap // 解构并展开 customDataMap 的内容
        }))
        if (data.data.length > 0) {
          const counts = {
            ys: 0, // 验收阶段
            yswc: 0, // 验收完成阶段
            sjcjzl: 0, // 数据采集治理阶段
            yz: 0, // 验证阶段
            zzyx: 0, // 正式运行阶段
            sys: 0, // 试运行阶段
            jm: 0, // 建模阶段
            sjjl: 0 // 数据积累阶段
          }
          data.data.forEach(item => {
            switch (item.milepostName) {
              case '验收':
                counts.ys++
                if (item.projectStatus === '完成') {
                  counts.yswc++ // 如果 projectStatus 为 完成，则验收完成数加 1
                }
                break
              case '验证':
                counts.yz++
                break
              case '正式运行':
                counts.zzyx++
                break
              case '试运行':
                counts.sys++
                break
              case '数据建模':
                counts.jm++
                break
              case '数据积累':
                counts.sjjl++
                break
              case '数据采集治理':
                counts.sjcjzl++
                break
              case '数据积累':
                counts.sjcjzl++
                break
              case '自学习表数据确认':
                counts.sjcjzl++
                break
              default:
                break
            }
          })

          // 赋值到 ftfState.num
          ftfState.num.ys = counts.ys
          ftfState.num.yswc = counts.yswc
          ftfState.num.yz = counts.yz
          ftfState.num.zzyx = counts.zzyx
          ftfState.num.sys = counts.sys
          ftfState.num.jm = counts.jm
          ftfState.num.sjjl = counts.sjjl
          ftfState.num.sjcjzl = counts.sjcjzl

          // 计算 total 总数
          ftfState.num.total = data.data.length
        }
        ftfState.modalVisible = true
      })
      .finally(() => {
        ftfState.tableLoading = false
      })
  }
  function changeData(record) {
    return
  }
  // 里程碑进度表弹窗
</script>
<style lang="less" scoped>
  .page_root {
  width: 100%;
  height: 100%;
  overflow: auto;
  }
  .page_root :deep(.@{ant-prefix}-spin-nested-loading),
  .page_root :deep(.@{ant-prefix}-spin-container)
   {
      height: 100%;
  }
  .page_root :deep(.@{ant-prefix}-spin-container .@{ant-prefix}-table-wrapper)
   {
      display: flex;
      flex-flow: column nowrap;
      justify-content: flex-start;
  }
  .page_root :deep(.@{ant-prefix}-table)
   {
    flex: auto;
    overflow: auto;
  }
  .table-moreBtn_down {
    overflow: hidden; white-space: nowrap; text-overflow: ellipsis; width: 100px;
  }

  .table-moreBtn_menu :deep(.table-moreBtn_menu-item):hover {
    background: #ebf1ff;
  }

  /*  表格树结构样式处理，展开按钮层级增加*/
  :deep(.@{ant-prefix}-table-row-expand-icon) {
    z-index: 1;
  }
  /*  表格树结构 由于每个表格项采用自定义组件，使用绝对定位布局，开启树结构导致显示异常，暂时使用层级定位位置 */
  :deep(.@{ant-prefix}-table-row-level-1 .@{ant-prefix}-table-cell-with-append .cell-wrapper-left) {
    left: 15px !important;
    width: calc(100% - 15px);
  }
  :deep(.@{ant-prefix}-table-row-level-2 .@{ant-prefix}-table-cell-with-append .cell-wrapper-left) {
    left: 30px !important;
    width: calc(100% - 30px);
  }
  :deep(.@{ant-prefix}-table-row-level-3 .@{ant-prefix}-table-cell-with-append .cell-wrapper-left) {
    left: 45px !important;
    width: calc(100% - 45px);
  }
  :deep(.@{ant-prefix}-table-row-level-4 .@{ant-prefix}-table-cell-with-append .cell-wrapper-left) {
    left: 60px !important;
    width: calc(100% - 60px);
  }

  /* 穿梭框改变默认样式，为根据组件样式控制左右栏宽度。 */
  :deep(.@{ant-prefix}-transfer-list)
   {
      height: 100%;
      width: 50%;
  }


  .img {
    display: inline-block;
    background-size: 100%;
    background-repeat: no-repeat;
  }
  .icon-green {
    background: url('@/assets/images/6ab2616ca12628e10d3c4ced66ef6d3d.svg');
  }
  .icon-yellow {
    background: url('@/assets/images/fea33e9131eb91976ed6122af567c76a.svg');
  }
  .icon-red {
    background: url('@/assets/images/b42a435f229f0bd0476d1499f8ee758c.svg');
  }
  .icon-data-sel {
    background: url('@/assets/images/222c56eae980a7215f762a8960fbead0.svg');
  }
  .icon-data {
    background: url('@/assets/images/c7320314e7e82ee8cf2e9bdc637dfbd6.svg');
  }
  .icon-pro {
    background: url('@/assets/images/89f0b358f8e057d5cb90e524acdf429e.svg');
  }
  .icon-pro-sel {
    background: url('@/assets/images/5663d7925478b17654621f717f6305bb.svg');
  }
  .icon-area {
    background: url('@/assets/images/8775dc8f36eacfd4e7452d828abf1be9.svg');
  }
  .icon-area-sel {
    background: url('@/assets/images/af9d47c90bff15ffbb5fecf2021e84ed.svg');
  }
  .icon-more{
   background: url('@/assets/images/6be604a73baba7651efb497101b0b964.svg');
  }
  .icon-more-sel{
   background: url('@/assets/images/8584ef8767de5f3efddfc0b9c6ec39b1.svg');
  }
  ul,
  li {
    padding: 0;
    margin: 0;
  }
  .top-title {
    height: 64px;
    background: url('@/assets/images/242a94e86ef48d58300b724953fd3631.svg');
    background-size: contain;
    background-position: center;
    background-repeat: no-repeat;
    display: flex;
    justify-content: center;
    align-items: center;
    font-family: PingFangSC-Semibold;
    font-size: 36px;
    color: #ffffff;
    letter-spacing: 10px;
    font-weight: 600;
  }
  .left-geo {
    position: absolute;
    cursor: pointer;
    z-index: 999;
    top: -24px;
    left: 16px;
    bottom: 24px;
    display: flex;
    flex-direction: column;
    li {
      line-height: 100%;
    }
    .proAreaSels {
      background-image: linear-gradient(179deg, rgba(218, 237, 255, 0.4) 0%, rgba(242, 253, 255, 0.4) 100%);
      box-shadow: 0 2px 10px 0 #d5e7ed;
      border-radius: 4px;
      border: 1px solid;
      border-image: linear-gradient(to bottom, #3875ff, #fff, #fff, #3875ff) 1;
      padding: 16px;
      max-width: 240px;
      min-width:200px;
      width:12vw;
      box-sizing: border-box;
      margin-top: 16px;
      flex: 1;
      .icon.img {
        width: 16px;
        height: 16px;
      }

      .unexpend {
        li {
          display: none;
        }
        .arrow-right {
          transform: rotate(90deg);
        }
      }
      .show-active {
        display: none;
      }
      .active {
        .arrow-right {
          border-left: 8px solid #3875ff;
        }
        .show-active {
          display: unset;
        }
        .hide-active {
          display: none;
        }
      }
      .name {
        border-radius: 2px;
        height: 32px;
        display: flex;
        align-items: center;
        padding: 0 9px;
        font-family: PingFangSC-Semibold;
        font-size: 16px;
        letter-spacing: 0;
        line-height: 32px;
        font-weight: 600;
        &.active {
          background: rgba(56, 117, 255, 0.1);
          color: #3875ff;
          .arrow-right {
            border-left: 8px solid #3875ff;
          }
        }
      }
      .icon {
        margin-right: 4px;
      }
      .arrow-right {
        display: inline-block;
        border-left: 8px solid #8c8c8c;
        border-top: 6px solid transparent;
        border-bottom: 6px solid transparent;
        transform: rotate(0deg);
      }
      li {
        display: flex;
        line-height: 32px;
        align-items: center;
        padding-left: 39px;
        font-family: PingFangSC-Regular;
        font-size: 14px;
        color: #595959;
        letter-spacing: 0;
        line-height: 32px;
        font-weight: 400;
        &.active {
          background: rgba(56, 117, 255, 0.1);
          color: #3875ff;
        }
        &.disabled{
          font-family: PingFangSC-Regular;
          font-size: 14px;
          color: #ACACAC;
          letter-spacing: 0;
          line-height: 32px;
          font-weight: 400;
          cursor: not-allowed;
        }
      }
    }
    .typeSels {
      background: #ffffff;
      border: 1px solid #3875ff;
      border-radius: 4px;
      font-size: 14px;
      color: #262626;
      letter-spacing: 0;
      text-align: center;
      line-height: 20px;
      font-weight: 400;
      display: inline-flex;
      width: 178px;
      li {
        flex: 1;
        display: inline-block;
        padding: 6px 16px;
        line-height: 20px;
        white-space: nowrap;
        &.action {
          background: #3875ff;
          color: #fff;
        }
      }
    }
  }
  .main-content {
    width: 100%;
    height: 100%;
    overflow:auto;
    position: relative;
    background-color: #fff;
    //border: 1px solid blue;
    background: url('@/assets/images/4e5500102dd3b5f283a2d424790207ff.svg');
    background-size: cover;
    background-repeat: no-repeat;
    background-position: center;
    *{
      user-select: none;
      -webkit-user-select: none;  /* Safari */
      -moz-user-select: none;     /* Firefox */
      -ms-user-select: none;      /* IE 10 and IE 11 */
    }
  }
  .content {
    padding: 0 16px;
    display: flex;
    justify-content: center;
    position: relative;
  }
  .echarts-content {
    margin-left: 7%;
    //border: 1px solid red;
    width: 1126px;
    height: 794px;
    position: relative;
    //border: 1px solid red;
    overflow: hidden;
    //transform: scale(1, 0.96);
    //transform: scale(1, 0.87);
    transform-origin: 0 0;
    .china-map-bg {
      position: absolute;
      top: 62px;
      left: 112px;
      width: 898px;
      height: 634px;
      transform: scale(1, 1.152);
      transform-origin: top;
      background: url('@/assets/images/0e9e661eaef818459b7aeba4247efe31.svg');
      background-size: cover;
    }
  }
  .legend {
    position: absolute;
    display: flex;
    align-items: center;
    justify-content: center;
    width: 100%;
    margin-top: 16px;
    z-index:9;
    li {
      display: flex;
      align-items: center;
      margin: 0 12px;
      cursor:pointer;
      &.gray{
        opacity: .56;
      }
      .icon {
        width: 24px;
        height: 24px;
        margin-right: 8px;
      }
    }
  }
  .echarts-main {
    width: 1126px;
    height: 2000px;
    position: relative;
    transform: translateY(-450px);
  }
  .fill {
    color: red;
  }

  ::v-deep .map-dialog {
    background: #ffffff;
    border: 1px solid #3875ff !important;
    box-shadow: 0 4px 0 0 rgba(56, 117, 255, 0.64) !important;
    border-radius: 2px 2px 2px 0 0 0 2px !important;
    font-family: PingFangSC-Regular;
    font-size: 14px !important;
    color: #262626 !important;
    letter-spacing: 0 !important;
    text-align: center !important;
    font-weight: 400 !important;

    .value{
      font-size: 10px;
    }
    .status-0{
      .value{
        color: #52c41a;
      }
    }
    .status-1{
      .value{
        color: #ff8c00;
      }
    }
    .status-2{
      .value{
        color: #f5222d;
      }
    }
  }

  ::v-deep .map-dialog::after,
  ::v-deep .map-dialog::before {
    content: '';
    position: absolute;
    bottom: -10px; /* 箭头的顶部位置，负数表示向上移动 */
    left: 50%; /* 箭头的水平中心位置 */
    margin-left: -10px; /* 将箭头水平居中对齐 */
    width: 0;
    height: 0;
    border-left: 10px solid transparent; /* 左边框透明 */
    border-right: 10px solid transparent; /* 右边框透明 */
    border-top: 10px solid #fff; /* 底边框设置箭头颜色和大小 */
  }

  ::v-deep .map-dialog::before {
    margin-left: -16px; /* 将箭头水平居中对齐 */
    bottom: -16px; /* 箭头的顶部位置，负数表示向上移动 */
    border-left: 16px solid transparent; /* 左边框透明 */
    border-right: 16px solid transparent; /* 右边框透明 */
    border-top: 16px solid rgba(56, 117, 255, 0.64); /* 底边框设置箭头颜色和大小 */
  }

  /*
  里程碑进度表样式
  */
  /*冯腾飞样式*/

  .kb-table-box:deep(.@{ant-prefix}-table-thead) > tr > th {
    background: #3875ff;
    color: #fff;
    font-weight: 600;
    padding: 0;
    border-right: 1px solid #d9d9d9 !important;
    position: relative;
  }
  .kb-table-box :deep(.@{ant-prefix}-table-tbody) tr > td {
    font-size: 14px;
    font-family: arial, helvetica, 'microsoft yahei';
    font-weight: 400;
    color: #262626;
    border-bottom: 1px solid #d9d9d9;
    padding: 0 5px;
    word-break: break-all;
  }
  .search-radio {
    margin-bottom: 16px;
  }
  .db-click-name {
    width: 120px;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
    height: 30px;
    line-height: 30px;
  }
  .omit-div,
  .omit-div-question,
  .omit-div-productionPlan,
  .omit-div-customerRelationship {
    width: 320px;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
    height: 100%;
    padding: 0 8px;
  }
  .plus-icon {
    position: absolute;
    right: 0;
    top: 0;
    cursor: pointer;
  }
  .progress-click {
    height: 30px;
    line-height: 30px;
    cursor: pointer;
    display: flex;
  }
  /*冯腾飞样式*/
</style>